package org.example.Proxy;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import io.vertx.core.Vertx;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.net.NetClient;
import io.vertx.core.net.NetSocket;
import lombok.extern.slf4j.Slf4j;
import org.example.RpcApp;
import org.example.config.RpcConfig;
import org.example.constant.ProtocolConstant;
import org.example.constant.RpcConstant;
import org.example.enums.ProtocolMessageSerializerEnum;
import org.example.enums.ProtocolMessageTypeEnum;
import org.example.fault.retry.RetryStrategy;
import org.example.fault.retry.RetryStrategyFactory;
import org.example.loadbalancer.LoadBalancer;
import org.example.loadbalancer.LoadBalancerFactory;
import org.example.model.RpcRequest;
import org.example.model.RpcResponse;
import org.example.model.ServiceMetaInfo;
import org.example.protocol.ProtocolMessage;
import org.example.protocol.ProtocolMessageDecoder;
import org.example.protocol.ProtocolMessageEncoder;
import org.example.registry.Registry;
import org.example.registry.RegistryFactory;
import org.example.serializer.Serializer;
import org.example.serializer.SerializerFactory;
import org.example.server.tcp.VertxTcpClient;

import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;

/**
 * @description TODO
 * @author sats@jz
 * @date 2024年12月30日 15:06
 */
@Slf4j
public class ServiceProxyWithTcp implements InvocationHandler {
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//        final Serializer serializer = SerializerFactory.getSerializer(RpcApp.getRpcConfig().getSerializer());

        RpcRequest rpcRequest = RpcRequest.builder()
                .serviceName(method.getDeclaringClass().getName())
                .methodName(method.getName())
                .parameterTypes(method.getParameterTypes())
                .args(args)
                .build();
        try {
            RpcConfig rpcConfig = RpcApp.getRpcConfig();
            Registry registry = RegistryFactory.getInstance(rpcConfig.getRegistryConfig().getRegistry());
            ServiceMetaInfo serviceMetaInfo = ServiceMetaInfo.builder()
                    .serviceName(method.getDeclaringClass().getName())
                    .serviceVersion(RpcConstant.DEFAULT_SERVICE_VERSION)
                    .build();

            List<ServiceMetaInfo> serviceMetaInfos = registry.serviceDiscovery(serviceMetaInfo.getServiceKey());
            if (CollUtil.isEmpty(serviceMetaInfos)) {
                throw new RuntimeException("暂无服务地址");
            }
//            ServiceMetaInfo selectedServiceMetaInfo = serviceMetaInfos.get(0);

            LoadBalancer loadBalancer = LoadBalancerFactory.getLoadBalancer(rpcConfig.getLoadBalancer());
            Map<String, Object> requestParams = new HashMap<>();
            requestParams.put("methodName", rpcRequest.getMethodName());
            ServiceMetaInfo selectedServiceMetaInfo = loadBalancer.select(requestParams, serviceMetaInfos);
            // 发送请求
            // 发送请求

//        Vertx vertx = Vertx.vertx();
//        NetClient netClient = vertx.createNetClient();
//        CompletableFuture<Object> objectCompletableFuture = new CompletableFuture<>();
//        netClient.connect(selectedServiceMetaInfo.getServicePort(), selectedServiceMetaInfo.getServiceHost(), res -> {
//            if (res.succeeded()) {
//                System.out.println("Connect to TCP server");
//                NetSocket socket = res.result();
//                // 发送消息
//                // 构造消息
//                ProtocolMessage<RpcRequest> protocolMessage = new ProtocolMessage<>();
//                ProtocolMessage.Header header = new ProtocolMessage.Header();
//                header.setMagic(ProtocolConstant.PROTOCOL_MAGIC);
//                header.setVersion(ProtocolConstant.PROTOCOL_VERSION);
//                String serializer1 = RpcApp.getRpcConfig().getSerializerName();
//                header.setSerializer((byte)ProtocolMessageSerializerEnum.getEnumByValue(serializer1).getKey());
//                header.setMessageType((byte) ProtocolMessageTypeEnum.REQUEST.getKey());
//                header.setRequestId(IdUtil.getSnowflakeNextId());
//                protocolMessage.setHeader(header);
//                protocolMessage.setBody(rpcRequest);
//
//                try {
//                    Buffer encoder = ProtocolMessageEncoder.encoder(protocolMessage);
//                    socket.write(encoder);
//                } catch (IOException e) {
//                    throw new RuntimeException("协议消息编码错误");
//                }
//                // 接受响应
//                socket.handler(buffer -> {
//                    try {
//                        ProtocolMessage<RpcResponse> rpcResponseProtocolMessage = (ProtocolMessage<RpcResponse>) ProtocolMessageDecoder.decoder(buffer);
//                        objectCompletableFuture.complete(rpcResponseProtocolMessage.getBody());
//                    } catch (IOException e) {
//                        throw new RuntimeException("协议消息解码错误");
//                    }
//                });
//            } else {
//                log.info("Failed to connect to TCP server");
//            }
//
//        });
//        RpcResponse rpcResponse  = (RpcResponse) objectCompletableFuture.get();
//        netClient.close();

            // 应用重试
            RetryStrategy retryStrategy = RetryStrategyFactory.getRetryStrategy(rpcConfig.getRetryStrategy());
            RpcResponse rpcResponse = retryStrategy.doRetry(() ->
                VertxTcpClient.doRequest(rpcRequest, selectedServiceMetaInfo);
            );
//            RpcResponse rpcResponse = VertxTcpClient.doRequest(rpcRequest, selectedServiceMetaInfo);
            return rpcResponse.getData();
        } catch (Exception e) {
            throw new RuntimeException("调用失败");
        }
    }
}
